package controllers

import java.net.{URLDecoder, URLEncoder}
import dao._

import javax.inject.Inject
import org.joda.time.DateTime
import play.api.libs.json.Json
import play.api.mvc._
import tool._
import models.Tables._
import play.api.Logger
import play.api.routing.JavaScriptReverseRouter
import utils.{DesEncrypter, Utils}
import utils.Utils.{Info, Sender}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import shared.pojo.Pojo.{ConfirmActive, Login, ValidData}
import upickle.default.writeJs
import implicits.Implicits._
import shared.pojo.Role

/** Created by yz on 2018/8/20
  */
class AppController @Inject() (
    cc: ControllerComponents,
    formTool: FormTool,
    accountDao: AccountDao,
    userDao: UserDao,
    tool: Tool,
    pdfInfoDao: PdfInfoDao
) extends AbstractController(cc) {

  def newPasswordActive = Action.async { implicit request =>
    val data = formTool.userNameForm.bindFromRequest().get
    userDao.selectByNameOrEmail(data.name).map(_.get).map { x =>
      Ok(writeJs(x.email))
    }
  }

  def login = Action.async { implicit request =>
    val data = formTool.userForm.bindFromRequest().get
    accountDao.selectById1
      .zip(userDao.selectByUserData(data))
      .map { case (account, optionUser) =>
        if (data.name == account.account && data.password == account.password) {
          Login.Response(valid = true, role = "admin")
        } else if (optionUser.isDefined) {
          val user = optionUser.get
          if (user.active == 0) {
            Login.Response(
              valid = true,
              activated = false,
              errorClass = Utils.errorClass,
              email = user.email
            )
          } else {
            Login.Response(
              valid = true,
              id = user.id,
              role = Role.User.entryName
            )
          }

        } else {
          Login.Response(valid = false, errorClass = Utils.errorClass)
        }
      }
      .map { x =>
        Ok(writeJs(x))
      }
  }

  def userNameCheck = Action.async { implicit request =>
    val data = formTool.userNameForm.bindFromRequest.get
    userDao.selectByName(data.name).zip(accountDao.selectById1).map {
      case (optionUser, admin) =>
        optionUser match {
          case Some(y) => Ok(Json.obj("valid" -> false))
          case None =>
            val valid = if (data.name == admin.account) false else true
            Ok(Json.obj("valid" -> valid))
        }
    }
  }

  def emailCheck = Action.async { implicit request =>
    val data = formTool.emailForm.bindFromRequest.get
    userDao.selectByEmail(data.email).zip(accountDao.selectById1).map {
      case (optionUser, admin) =>
        optionUser match {
          case Some(y) => Ok(Json.obj("valid" -> false))
          case None =>
            val valid = if (data.email == admin.email) false else true
            Ok(Json.obj("valid" -> valid))
        }
    }
  }

  def phoneCheck = Action.async { implicit request =>
    val data = formTool.phoneForm.bindFromRequest.get
    userDao.selectByPhone(data.phone).zip(accountDao.selectById1).map {
      case (optionUser, admin) =>
        optionUser match {
          case Some(y) => Ok(Json.obj("valid" -> false))
          case None =>
            Ok(Json.obj("valid" -> true))
        }
    }
  }

  def register = Action.async { implicit request =>
    val data = formTool.registerUserForm.bindFromRequest().get
    val row = UserRow(
      0,
      data.name,
      data.fullName,
      data.password,
      data.unit,
      data.email,
      data.phone,
      Some(0),
      None,
      None,
      new DateTime(),
      0
    )
    userDao.insertAndReturning(row).flatMap { userId =>
      val pdfInfoRow = PdfInfoRow(userId, "深圳绘云医学检验实验室", "", "", "", "")
      pdfInfoDao.insert(pdfInfoRow).map { x =>
        val response = ValidData(valid = true)
        Ok(writeJs(response))
      }
    }
  }

  def sendEmail = Action.async { implicit request =>
    val data = formTool.emailForm.bindFromRequest().get
    userDao.selectSomeByEmail(data.email).map { x =>
      Future {
        val codeEmail = tool.registerDesEncrypter.encrypt(data.email)
        val href =
          s"http://${request.domain}:8080/#/confirmActive?email=${Utils.urlEncode(codeEmail)}"
        val content =
          s"""
             |感谢您的注册！您需要验证您的电子邮件以后才能正常使用账户：<br>
             |----------------------------------<br>
             |用户名：${x.name}<br>
             |----------------------------------<br>
             |点击链接激活您的账户<br>
             |<a href="${href}">${href}</a><br>
             |激活成功后，请等待管理员授权后使用！<br>
             |如果您无法直接访问此链接，请复制粘贴此链接到浏览器地址栏进行访问！<br>
             |如果不是本人操作，请忽略此邮件。<br>
             |<br>
             |Regards,<br>
             |绘云生物科技
       """.stripMargin
        val info = Info("LiveForest账户激活通知", content)
        val inbox = data.email
        Utils.sendEmailBySsl(Utils.sender, info, inbox)
      }
      val response = ValidData(valid = true)
      Ok(writeJs(response))
    }

  }

  def newPasswordBefore = Action.async { implicit request =>
    val data = formTool.emailForm.bindFromRequest().get
    val email = tool.newPasswordDesEncrypter.decrypt(data.email)
    userDao.selectSomeByEmail(email).map { x =>
      Ok(writeJs(x.name))
    }
  }

  def newPassword = Action.async { implicit request =>
    val data = formTool.newPasswordForm.bindFromRequest().get
    userDao.selectSomeByName(data.name).flatMap { x =>
      val row = x.copy(password = data.newPassword)
      userDao.update(row).map { y =>
        val response = ValidData(valid = true)
        Ok(writeJs(response))
      }
    }
  }

  def newPasswordEmailValid = Action.async { implicit request =>
    val data = formTool.emailForm.bindFromRequest().get
    userDao.selectSomeByEmail(data.email).map { x =>
      Future {
        val codeEmail = tool.newPasswordDesEncrypter.encrypt(data.email)
        val href =
          s"http://${request.domain}:8080/#/newPassword?email=${Utils.urlEncode(codeEmail)}"
        val content =
          s"""
             |下面是您的原用户名信息，点击下面的链接重置密码：<br>
             |----------------------------------<br>
             |用户名：${x.name}<br>
             |----------------------------------<br>
             |点击链接重置修改密码。<br>
             |<a href="${href}">${href}</a><br>
             |如果您无法直接访问此链接，请复制粘贴此链接到浏览器地址栏进行访问！<br>
             |如果不是本人操作，请忽略此邮件。<br>
             |<br>
             |Regards,<br>
             |绘云生物科技
       """.stripMargin
        val info = Info("LiveForest找回密码通知", content)
        val inbox = data.email
        Utils.sendEmailBySsl(Utils.sender, info, inbox)
      }
      val response = ValidData(valid = true)
      Ok(writeJs(response))
    }

  }

  def registerActive = Action.async { implicit request =>
    val data = formTool.emailForm.bindFromRequest().get
    val email = tool.registerDesEncrypter.decrypt(data.email)
    userDao
      .selectSomeByEmail(email)
      .flatMap { x =>
        if (x.active == 1) {
          Future {
            ConfirmActive.Response(hasActived = true)
          }
        } else {
          val row = x.copy(active = 1)
          userDao.update(row).map { y =>
            val data = row
            Future {
              val content =
                s"""
                 |有新用户注册成功！该用户信息如下：<br>
                 |用户名：${data.name}<br>
                 |姓名: ${data.fullName}<br>
                 |单位: ${data.unit}<br>
                 |邮箱: ${data.email}<br>
                 |手机: ${data.phone}
       """.stripMargin
              val info = Info("LiveForest新用户注册成功通知", content)
              val account = Utils.execFuture(accountDao.selectById1)
              val inbox = account.email
              Utils.sendEmailBySsl(Utils.sender, info, inbox)
            }
            ConfirmActive.Response(hasActived = false)
          }
        }
      }
      .map { response =>
        Ok(writeJs(response))
      }

  }

  def validName = Action.async { implicit request =>
    val data = formTool.userNameForm.bindFromRequest().get
    userDao.selectByNameOrEmail(data.name).map { x =>
      val valid = if (x.isDefined) true else false
      Ok(Json.toJson(valid))
    }
  }

  def javascriptRoutes = Action { implicit request =>
    Ok(
      JavaScriptReverseRouter("jsRoutes")(
        controllers.routes.javascript.PredictController.predictResult,
        controllers.routes.javascript.PredictController.predict,
        controllers.routes.javascript.PredictController.batchPredict,
        controllers.routes.javascript.MissionController.deleteMissionById,
        controllers.routes.javascript.MissionController.getAllMission,
        controllers.routes.javascript.MissionController.deleteMissionByIds,
        controllers.routes.javascript.AdminController.getAllUser,
        controllers.routes.javascript.AdminController.deleteUserById,
        controllers.routes.javascript.AdminController.updateUser,
        controllers.routes.javascript.AdminController.addDays
      )
    ).as("text/javascript")
  }

}
